/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.unb.core.manager;

import java.util.HashMap;
import java.util.Iterator;

import br.unb.core.message.Message;
import br.unb.core.traffic.Traffic;
import br.unb.utils.Resource;

/**
 *
 * @author spider
 */
public class TrafficManager {

    /*Instance*/
    private static final TrafficManager INSTANCE = new TrafficManager();

    private TrafficManager() {
    }

    static TrafficManager getInstance() {
        return INSTANCE;
    }
    static final ManagerSocket MANAGER_SOCKET = ManagerSocket.getInstance();
    /** Traffic map, used by the controller machine */
    public final HashMap trafficMap = new HashMap();
    //public static final HashMap receiversMap = new HashMap();
    //public static final HashMap sendersMap = new HashMap();

    public HashMap getTrafficMap() {
        return trafficMap;
    }

    /*********************** Controller machine ******************************/
    /**
     * (Executed on Controller machine)
     * Sends a control message to the network the first time a traffic is run to
     * setup variables on the sender and the receiver.
     * @param traffic traffic to be initiated on the target machines
     */
    void newTraffic(Traffic traffic) {
        if (traffic == null) {
            Manager.getInstance().printError("Controller machine: null traffic passed! nothing to do ");
            return;
        }

        Traffic t = (Traffic) trafficMap.get(traffic.getName());
        if (t == null) {
            t = traffic;
            trafficMap.put(traffic.getName(), traffic);
        }
        //Resource.print("Controller machine: prepareTraffic()! ");//debug

        Message responseFromReceiver = MANAGER_SOCKET.sendControlMessage(
                new Message(Message.Type.PREPARE_TO_RECEIVE, traffic), traffic.getDstIP(),
                1);
        if (Message.verifyError(responseFromReceiver)) {
            return;
        }

        Message responseFromSender = MANAGER_SOCKET.sendControlMessage(
                new Message(Message.Type.PREPARE_TO_SEND, traffic), traffic.getSrcIP(),
                1);

        if (Message.verifyError(responseFromSender)) {
            //If something wrong happens on sender, cancel the receiver too.
            //need to debug this!! REALLY
            Message extra = MANAGER_SOCKET.sendControlMessage(
                    new Message(Message.Type.STOP_RECEIVER, traffic.getName()),
                    traffic.getDstIP(),
                    3);
            Manager.getInstance().printError(extra.toString());
        }
    }

    /**
     * (Executed on Controller machine)
     * Sends a control message to the network to start the sender and receiver machines
     * @param traffic traffic to be initiated on the target machines
     */
    void playGenericTraffic(String key, boolean isRealTime) {
        Traffic t = (Traffic) trafficMap.get(key);
        /*Resource.print("Controller machine: startTraffic()! "
        + t.getName());
         */

        Message responseFromSender = MANAGER_SOCKET.sendControlMessage(
                new Message(Message.Type.START_SENDER, t.getName()),
                t.getSrcIP(),
                3);

        //Message.verifyError(responseFromSender);
    }

    /**
     * (Executed on Controller machine)
     * Sends a control message to start all traffics on all machines
     */
    void playAll(boolean isRealTime) {
        Iterator it = trafficMap.keySet().iterator();
        while (it.hasNext()) {
            playGenericTraffic((String) it.next(), isRealTime);
        }
    }

    /**
     * (Executed on controller machine)
     * Sends a control message to the network to stop the traffic on
     * the sender and receiver machines.
     * @param traffic traffic to be removed
     */
    void stopTraffic(String key) {
        Traffic t = (Traffic) trafficMap.get(key);

        /*Resource.print("Controller machine: stopTraffic()! "
        + t.getName());//debug
         */
        Message responseFromSender = MANAGER_SOCKET.sendControlMessage(
                new Message(Message.Type.STOP_SENDER, t.getName()),
                t.getSrcIP(),
                3);

        //Message.verifyError(responseFromSender);

        Message responseFromReceiver = MANAGER_SOCKET.sendControlMessage(
                new Message(Message.Type.STOP_RECEIVER, t.getName()),
                t.getDstIP(),
                3);
        //Message.verifyError(responseFromReceiver);
    }

    /**
     * (Executed on controller machine)
     * Stop all traffics on all machines
     */
    void stopAllTraffic() {
        Manager.getInstance().printError(Resource.getString("WAS_ASKED_TO_CLOSE_ALL_TRAFFICS"));
        Iterator it = trafficMap.keySet().iterator();
        while (it.hasNext()) {
            stopTraffic((String) it.next());
        }
        Runtime.getRuntime().gc();
    }
}
